package com.x52im.rainbowchat.http.logic.logic;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.eva.epc.common.util.CommonUtils;
import com.eva.epc.common.util.RestHashMap;
import com.eva.framework.Processor;
import com.eva.framework.dbpool.DBDepend;
import com.eva.framework.dbpool.DBShell;
import com.eva.framework.utils.EndsExceptionFactory;
import com.eva.framework.utils.LoggerFactory;
import com.x52im.rainbowchat.MyControllerJSONP;
import com.x52im.rainbowchat.http.logic.AbstractJobDispatcher;
import com.x52im.rainbowchat.http.logic.LogicProcessor2;
import com.x52im.rainbowchat.http.logic.LogicUtils;
import com.x52im.rainbowchat.http.logic.dto.OfflineMsgDTO;
import com.x52im.rainbowchat.http.logic.dto.RosterElementEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Vector;

public class MessagesJobDispatcher extends AbstractJobDispatcher {
    DBShell db = LogicProcessor2.db;

    /**
     * 维护消息管理.
     *
     * @param action_id 维护类型，SysConstant中的操作类型常量
     * @param newData   客端发送过来的本次修改新数据(可能为空，理论上与oldData不会同时空）
     * @param oldData   客端发送过来的本次修改前的老数据(可能为空，理论上与newData不会同时空）
     * @param userName  操作者的用户名
     * @return 返回给客户端的对象
     */
    @Override
    public String dispatch(int action_id, Object newData, Object oldData, Processor.User user) throws Exception {
        switch (action_id) {
            // 【接口1008-4-7】获取离线状态下好友发过来的加好友请求列表
            // FIXME: 性能优化点：以下查询其实可以一条SQL搞定，但目前为了简化字段解析代码而如此使用，以后再考虑进行查询优化（合并查询）
            case ACTION_APPEND1: {
                return ACTION_APPEND1(newData);
            }
            // 【接口1008-4-8】获取离线聊天消息
            case ACTION_APPEND2: {
                return ACTION_APPEND2(newData);
            }
            // 【接口1008-4-9】获取未处理的加好友请求总数
            // ·版本信息：since v4.5
            // ·用途说明：用于从服务端读取未处理的加好友请求总数量；
            // ·适用范围：当对接RainbowChat-Web产品时，本接口将被用于Web端。本接口后绪也将
            //           被用于替换现版Android和iOS里读取未处理好友总数的实现代码，当前暂未使用；
            case ACTION_APPEND3: {
                return ACTION_APPEND3(newData);
            }

            // 【接口1008-4-22】:删除个人全部聊天消息记录（已用于：Web端，目前其它端暂时用不上本接口）  - @since 4.5
            //  支持：删除一对一好友或陌生人聊天记录（即删除“我”与指定uid用户的记录）、群聊记录
            // ·用途说明：用于删除服务端存储的与某人或某群的全部聊天记录；
            // ·适用范围：当对接RainbowChat-Web产品时，本接口将被用于Web端（特别注意：因Android
            //           和iOS这类富客户，聊天记录都是存本地的，所以严格来说移动端不需要也没必要使用
            //           接口，本接口完全是为了对接Web产品时为其准备的）；
            case ACTION_APPEND4: {
                return ACTION_APPEND4(newData);
            }
            // 【接口1008-4-23】删除单条聊天消息记录（已用于：Web端，目前其它端暂时用不上本接口）  - @since 7.3
            // ·特别说明：本接口是真正的物理删除，不是转储哦！
            // ·用途说明：用于删除服务端存储的与某人或某群的单条聊天记录；
            // ·适用范围：当对接RainbowChat-Web产品时，本接口将被用于Web端（特别注意：因Android
            //           和iOS这类富客户，聊天记录都是存本地的，所以严格来说移动端不需要也没必要使用
            //           接口，本接口完全是为了对接Web产品时为其准备的）；
            case ACTION_APPEND5: {
                return ACTION_APPEND5(newData);
            }

            /**
             * 收藏消息
             */
            case ACTION_APPEND6: {
                return ACTION_APPEND6(newData);
            }

            /**
             * 收藏消息读取
             */
            case ACTION_APPEND7: {
                return ACTION_APPEND7(newData);
            }

            /**
             * 收藏消息删除
             */
            case ACTION_APPEND8: {
                return ACTION_APPEND8(newData);
            }

            default:
                throw EndsExceptionFactory.INVALID_ACTION_ID(action_id);
        }
    }

    private String ACTION_APPEND8(Object newData) throws Exception {
        JSONObject nwObj = JSONObject.parseObject((String) newData);
        String parentFps = nwObj.getString("parentFps");
        String userUid = nwObj.getString("userUid");
        String[] parentFpsArr = parentFps.split(",");

        StringBuffer sbf = new StringBuffer();
        for (int i = 0; i < parentFpsArr.length; i++) {
            sbf.append("'").append(parentFpsArr[i]).append("',");
        }
        sbf.setLength(sbf.length() - 1);
        String sql = String.format("delete from missu_user_msgs_collect_favorites where user_uid =%s and parent_fp in (%s)", userUid, sbf.toString());

        Vector sqls = new Vector();
        sqls.add(sql);
        boolean b = db.update(sqls, true);
        return b ? "1" : "0";
    }

    private String ACTION_APPEND6(Object newData) throws Exception {
        JSONObject nwObj = JSONObject.parseObject((String) newData);
        String parentFps = nwObj.getString("parentFps");
        String userUid = nwObj.getString("userUid");
        String[] parentFpsArr = parentFps.split(",");
        Vector sqls = new Vector();
        Vector values = new Vector();
        for (int i = 0; i < parentFpsArr.length; i++) {
            String sql = "INSERT INTO missu_user_msgs_collect_favorites(parent_fp, user_uid, state_date) VALUES(?, ?, now())";
            sqls.add(sql);
            values.add(new Object[]{parentFpsArr[i], userUid});
        }
        boolean b = db.update(sqls, values, true);
        return b ? "1" : "0";
    }

    private String ACTION_APPEND7(Object newData) throws Exception {
        JSONObject nwObj = JSONObject.parseObject((String) newData);
        String userUid = nwObj.getString("userUid");
        String sql = "select case " +
                "when x.chat_type = 0 then (select us.nickname from missu_users us where us.user_uid=x.dest_uid) " +
                "when x.chat_type = 2 then (select gb.g_name from group_base gb where gb.g_id=x.dest_uid) " +
                "end as nick_name, x.* from (" +
                "select a.create_date, b.* from missu_user_msgs_collect_favorites a, missu_user_msgs_collect b " +
                "where a.user_uid =" + userUid + " and a.state ='0' and a.parent_fp =b.fingerprint " +
                "union " +
                "select a.create_date, b.* from missu_user_msgs_collect_favorites a, missu_user_msgs_collect_archived b " +
                "where a.user_uid =" + userUid + " and a.state ='0' and a.parent_fp =b.fingerprint" +
                ") x order by x.create_date desc ";
        List<Map<String, Object>> list = db.queryDataListMap(sql);
        return JSON.toJSONString(list);
    }

    private String ACTION_APPEND1(Object newData) throws Exception {
        ArrayList<RosterElementEntity> allRequestFriendsInfo = new ArrayList<RosterElementEntity>();

        String localUid = (String) newData;
        StringBuffer sb = new StringBuffer();
        sb.append("select a.user_uid,a.be_timestamp,a.be_desc from missu_friendreq a ")
                .append("join missu_users b on a.be_user_uid=b.user_uid ")
                .append("where b.user_uid=" + localUid + " order by a.be_time desc");

        Vector<Vector> vec = db.queryData(sb.toString());
        if (vec.size() > 0) {
            for (Vector row : vec) {
                // 解析行数据并构建对象
                RosterElementEntity ree = constructOfflineAddFriendReqObj(row);
                if (ree != null) {
                    allRequestFriendsInfo.add(ree);
                }
            }
        }

        return JSON.toJSONString(allRequestFriendsInfo);
    }

    private String ACTION_APPEND2(Object newData) throws Exception {
        ArrayList<OfflineMsgDTO> allRequestFriendsInfo = new ArrayList<OfflineMsgDTO>();

        JSONObject nwObj = JSONObject.parseObject((String) newData);
        // 离线消息所有者的uid
        String user_uid = nwObj.getString("user_uid");
        // 离线消息由谁发送的uid（此参数为null则表示读取离线消息所有者的所有
        // 离线消息，否则表示只取指定的发送人发的离线消息）
        String from_user_uid = nwObj.getString("from_user_uid");
        // 离线消息中是否带上该消息在实时发送时的指纹码（目前仅在ios端、Andriod端需要
        // ，其它端暂未用到，请忽略本参数或传“0”即可）
        String includeFingerPring = nwObj.getString("include_fp");
        boolean isIncludeFingerPring = "1".equals(includeFingerPring);

        StringBuilder sb = new StringBuilder()
                .append("select ")
                .append("	a.user_uid")
                .append("   ,b.nickname")
//				.append("	,b.user_mail" )
                .append("	,a.friend_user_uid")
//				.append("	,c.user_mail" )
                .append("	,a.history_type")
                .append("	,a.history_content")
//				.append("	,a.history_content2" )
                .append("	,a.history_time2")
                .append("	,a.chat_type")
                .append("	,a.group_id")  // 只对群聊消息有意义（且只在群聊消息时不为null）
                .append("	,d.g_name")    // 只对群聊消息有意义
                .append(isIncludeFingerPring ? ",a.history_content2 as fp" : ",null as fp")
                .append("	,a.parent_fp") // 只对群聊消息有意义
                .append(" from missu_offline_history a ")
                .append(" left join missu_users b on a.user_uid = b.user_uid ")
//				.append(" left join missu_users c on a.friend_user_uid = c.user_uid " +
                .append(" left join group_base d on a.group_id = d.g_id ")
                .append(" where a.friend_user_uid = '" + user_uid + "'")
                // 为null则表示读取离线消息所有者的所有离线消息，否则表示只取指定的发送人发的离线消息
                .append((from_user_uid == null ? "" : " and a.user_uid='" + from_user_uid + "'"))
                .append(" order by a.history_time");

        String sql = sb.toString();

        Vector<Vector> vec = db.queryData(sql);
        if (vec.size() > 0) {
            for (Vector row : vec) {
                OfflineMsgDTO tempChatMsg = new OfflineMsgDTO();
                int i = 0;
                tempChatMsg.setUser_uid((String) row.get(i++));
                tempChatMsg.setNickName((String) row.get(i++));
//						tempChatMsg.setUser_mail((String) row.get(i++));
                tempChatMsg.setFriend_user_uid((String) row.get(i++));
//						tempChatMsg.setFriendUserMail((String) row.get(i++));
                tempChatMsg.setMsg_type(Integer.valueOf((String) row.get(i++)));
                tempChatMsg.setMsg_content((String) row.get(i++));
//						tempChatMsg.setMsg_content2((String) row.get(i++));
                tempChatMsg.setHistory_time2((String) row.get(i++));
                tempChatMsg.setChat_type((String) row.get(i++));
                tempChatMsg.setGroup_id((String) row.get(i++));
                tempChatMsg.setGroup_name((String) row.get(i++));

                tempChatMsg.setMsg_content2((String) row.get(i++));
                tempChatMsg.setParent_fp((String) row.get(i++));

                allRequestFriendsInfo.add(tempChatMsg);
            }
        }

        Vector sqls = new Vector();
        Vector values = new Vector();
        // 获取完离线消息后，就需要把水从离线列表中删除了哦
        sqls.add("delete from missu_offline_history where friend_user_uid = ?"
                // 为null则表示读取离线消息所有者的所有离线消息（不区分好友），
                // 否则表示只取指定的发送人发的离线消息
                + (from_user_uid == null ? "" : " and user_uid='" + from_user_uid + "'"));
        values.add(new Object[]{user_uid});

        db.update(sqls, values, false);

        return JSON.toJSONString(allRequestFriendsInfo);
    }

    private String ACTION_APPEND3(Object newData) throws Exception {
        String localUid = (String) newData;

        //** 未处理的加好友请求总数量
        StringBuffer sb = new StringBuffer();
        sb.append("select count(a.user_uid) as cnt from missu_friendreq a ")
                .append("join missu_users b on a.be_user_uid=b.user_uid ")
                .append("where b.user_uid=?");
        // 提示：请坚持使用预编译SQL语句，不够精简，但JDBC会自动处理SQL注入风险，保证安全性！
        Vector<Vector> vecs = db.queryData(sb.toString(), new Object[]{localUid});
        // 解析查询结果
        String cnt = (String) (vecs.get(0).get(0));//db.querySingleItem(sb.toString());
        int cntInt = CommonUtils.getIntValue(cnt, 0);

        //** 取出最后一个加好友的请求数据（方便客户端的ui上显示）
        boolean isSQLServer = DBShell.isSQLServer();
        boolean isMySQL = DBShell.isMySQL();
        StringBuffer sb2 = new StringBuffer();
        sb2.append("select " + (isSQLServer ? "top 1" : "") + " a.user_uid,a.be_timestamp,a.be_desc from missu_friendreq a ")
                .append("join missu_users b on a.be_user_uid=b.user_uid ")
                .append("where b.user_uid=? order by a.be_time desc " + (isMySQL ? "limit 0,4" : ""));
        Vector<Vector> vecs2 = db.queryData(sb2.toString(), new Object[]{localUid});
        // 解析行数据并构建对象
        RosterElementEntity offlineAddFriendReqObj = null;
        if (vecs2.size() > 0) {
            offlineAddFriendReqObj = constructOfflineAddFriendReqObj(vecs2.get(0));
        }

        //** 返回给客户端的数据
        RestHashMap<String, Object> m = RestHashMap.n();
        // 未处理的请求总数
        m.p("req_count", String.valueOf(cntInt));
        // 最近一个加好友请求的数据封装对象
        if (offlineAddFriendReqObj != null) {
            m.putField("latest_req_obj", "" + JSON.toJSONString(offlineAddFriendReqObj));
        }

        return JSON.toJSONString(m);
    }


    private String ACTION_APPEND4(Object newData) throws Exception {
        // 客户端传过来的数据
        JSONObject nwObj = JSONObject.parseObject((String) newData);

        String gid = nwObj.getString("gid");   // 删除群聊记录必填参数：要删除聊天记录的群id

        String luid = nwObj.getString("luid"); // 删除单聊和群聊记录必填参数：local uid（即“我”的uid）
        String ruid = nwObj.getString("ruid"); // 删除单聊记录选填参数：remote uid（即“对方”的uid）

        // true表示当前要删除的是群聊消息记录，否则表示要删除的一对一聊天记录
        boolean isDeleteGroupChatting = (!CommonUtils.isStringEmpty(gid, true));

        Vector sqls = new Vector();
        Vector values = new Vector();

        String ret = "0"; // 返回值：“0”表示失败、“1”表示成功

        try {
            // 要“删除”的是群聊聊天记录
            // 说明：群聊消息不是真的从物理上删除，只是逻辑上实现“删除”而已
            if (isDeleteGroupChatting) {
                // 更新此人在群内的消息起始时间即可实现消息的逻辑“删除”
                sqls.add("update group_members set msg_time_start=" + DBDepend.getDefaultDatetimeFunc() + " where g_id=? and user_uid=?");
                values.add(new Object[]{gid, luid});

                // 提交数据库执行
                db.update(sqls, values, true);
            }
            // 要“删除”的是单聊聊天记录
            else {
                //********************* 先尝试存档聊天记录和删除未拉取的离线消息 *********//
                LogicUtils.prepareDeleteSingleChattingMsg(sqls, values, luid, ruid);

                // 提交数据库执行
                db.update(sqls, values, false);
            }

            ret = "1"; // 成功
        } catch (Exception e) {
            LoggerFactory.getLog().warn("发生在删除与某人或某群的全部聊天记录时：", e);
        }

        return ret;
    }

    private String ACTION_APPEND5(Object newData) throws Exception {
        LoggerFactory.getLog().debug("==【【【【【【【正在删除单条聊天消息。。。】】】】】】】==");
        JSONObject nwObj = JSONObject.parseObject((String) newData);
        String fpForMessage = nwObj.getString("fp_for_message");

        Vector sqls = new Vector();
        Vector values = new Vector();
        sqls.add("delete from missu_user_msgs_collect where fingerprint=?");
        values.add(new Object[]{fpForMessage});
        boolean res = db.update(sqls, values, false);
        return res ? "1" : "0";// 1 表示更新成功，否则失败
    }

    /**
     * 从查询出来的数据库行中解析并构建离线好友请求数据对象（供客户端使用）。
     *
     * @param row
     * @return
     * @throws Exception
     */
    private RosterElementEntity constructOfflineAddFriendReqObj(Vector row) throws Exception {
        if (row != null) {
            String reqSrcUid = (String) row.get(0);
            String reqTime = (String) row.get(1);
            String saySomethingFromHim = (String) row.get(2);

            RosterElementEntity ree = LogicUtils.queryUserInfoByUID(reqSrcUid, null);
            if (ree != null) {
                // 自20140213 RainbowChat2.2（含）以后ex1作为服务端转发加好友请求（给B）时存放“验证说明文本”使用（包括离线消息）
                ree.setEx1(MyControllerJSONP.JSONSave(saySomethingFromHim));
                // 自20171225 RainbowChat4.2（含）以后ex10作为服务端转发加好友请求（给B）时存放“好友请求发起时间戳”使用（包括离线消息）
                // 自20180507 RBv4.3以后，本字段存放的是时间戳，而非人类可读的时间字串
                ree.setEx10(reqTime);
            }

            return ree;
        }

        return null;
    }
}
